ASSERT(mfn_valid(gmfn));
/* We should never try to promote a gmfn that has writeable mappings */
- ASSERT(sh_remove_write_access(v, gmfn, 0, 0) == 0);
+ ASSERT((page->u.inuse.type_info & PGT_type_mask) != PGT_writable_page
+ || (page->u.inuse.type_info & PGT_count_mask) == 0
+ || v->domain->is_shutting_down);
/* Is the page already shadowed? */
if ( !test_and_set_bit(_PGC_page_table, &page->count_info) )
perfc_incr(shadow_writeable_bf);
hash_foreach(v, callback_mask, callbacks, gmfn);
- /* If that didn't catch the mapping, something is very wrong */
+ /* If that didn't catch the mapping, then there's some non-pagetable
+ * mapping -- ioreq page, grant mapping, &c. */
if ( (mfn_to_page(gmfn)->u.inuse.type_info & PGT_count_mask) != 0 )
{
- SHADOW_ERROR("can't find all writeable mappings of mfn %lx: "
- "%lu left\n", mfn_x(gmfn),
+ SHADOW_ERROR("can't remove write access to mfn %lx: guest has "
+ "%lu special-use mappings of it\n", mfn_x(gmfn),
(mfn_to_page(gmfn)->u.inuse.type_info&PGT_count_mask));
domain_crash(v->domain);
}
if ( guest_walk_tables(v, va, &gw, 1) != 0 )
{
- SHADOW_PRINTK("malformed guest pagetable!");
+ SHADOW_PRINTK("malformed guest pagetable\n");
print_gw(&gw);
}
+ /* It's possible that the guest has put pagetables in memory that it has
+ * already used for some special purpose (ioreq pages, or granted pages).
+ * If that happens we'll have killed the guest already but it's still not
+ * safe to propagate entries out of the guest PT so get out now. */
+ if ( unlikely(d->is_shutting_down) )
+ {
+ SHADOW_PRINTK("guest is shutting down\n");
+ shadow_unlock(d);
+ return 0;
+ }
+
sh_audit_gw(v, &gw);
// We do not look at the gw->l1e, as that will not exist for superpages.